import { RVOMath, Vector2 } from "../RVO/Common"
import { AgentParam, Simulator } from "../RVO/Simulator"
import QuadTree, { circle } from "../QuadTree"
import {
    GBulletLiveTime, GBulletRadius, GEnemyHP, GMoveSpeed, GSEnemySKillCD, rotateAroundCenter, ExpTypeEnum, G, IExp, GWeapon3BulletAttr,
    GWeaponBullet, GWeaponShootRadiu, IEnemy, IState, ITimePass, IVec2, IWeapon, EntityTypeEnum, StateTypeEnum, angelToRadian,
    randomBySeed, vecToAngel, distance, GWeaponMuzzle, rotate, Singleton, IActorMove, get3PointDisFar, GEnemyDisPlayer, IActor,
    getPointInCircleByPoint, distanceSqu, IEnemySkill, GEnemyImpact, deepClone, GWeapon1BulletAttr, toFixed, GChapter, GLevelPart,
    IRedX, GExp, IBullte, GEnemy, EnemyTypeEnum, EnemyMoveTypeEnum, EnemySkillTypeEnum, GEnemyImpactPlus, IWeaponAttr, ActorSkillTypeEnum,
    getDirByPos, LevelTypeEnum, GEntity, EntityTypeEnum2
} from "../index"
import { BehaviorManager } from "../BehaviorTree/BehaviorManager"
import Boss1Tree from "../BehaviorTree/Biz/Tree/Boss1Tree"
import { DamageCountManager } from "./DamageCountManager"
import Boss2Tree from "../BehaviorTree/Biz/Tree/Boss2Tree"
import { AttributeManager } from "./AttributeManager"
import { SkillManager } from "./SkillManager"
import { HPManager } from "./HPManager"
import DataManager from "../../Runtime/DataManager"
import BagManager from "../../Runtime/BagManager"
import { TalentManager } from "../../Runtime/TalentManager"

export class GameLogic extends Singleton {
    static get Ins() {
        return super.GetInstance<GameLogic>()
    }
    constructor() {
        super()
        this.simulator = new Simulator()
    }
    state: IState = DataManager.Ins.defaultState
    quadTree: QuadTree = new QuadTree({
        x: -G.StageSize.w / 2,
        y: -G.StageSize.h / 2,
        w: G.StageSize.w,
        h: G.StageSize.h,
    }, 1)
    behaviorTreeMap: Map<number, BehaviorManager> = new Map()
    enemyMap: Map<number, IEnemy> = new Map()
    simulator: Simulator
    tick(input: ITimePass, state: IState, quadTree: QuadTree, behaviorTreeMap: Map<number, BehaviorManager>, simulator: Simulator): { state: IState, simulator: Simulator } {
        try {
            this.simulator = simulator
            this.behaviorTreeMap = behaviorTreeMap
            const dt = toFixed(input.dt)
            this.setInitParam(input, state, quadTree)

            this.resetState(dt)
            this.scrollTick(dt)
            this.setPreferredVelocities()
            this.simulator.run(dt)
            this.enemyTick(dt)

            this.behaviorTreeTick(dt)
            this.enemySkillTick(dt)
            this.enemyBuffTick(dt)
            this.weaponTick(dt)
            this.bulletTick(dt)
            this.expTick()
            this.redXTick(dt)
            this.actorTick(dt)
            this.regenerationTick(dt)
            this.gameTick(dt)
        } catch (error) {
            console.log('tick', error)
        }
        return { state, simulator }
    }

    /** 重置一些状态 */
    resetState(dt: number) {

        /** 同步射击技能状态 */
        const tbsjSkill = this.state.skill[ActorSkillTypeEnum.tbsj]
        if (tbsjSkill) {
            const data7 = tbsjSkill.data[EntityTypeEnum.weapon7]
            const data8 = tbsjSkill.data[EntityTypeEnum.weapon8]
            data7.state = StateTypeEnum.none
            data8.state = StateTypeEnum.none
            data7.time -= dt
            data8.time -= dt
        }
    }

    /** 设置一些参数 */
    setInitParam(input: ITimePass, state: IState, quadTree: QuadTree) {
        this.state = state
        this.quadTree = quadTree
        this.enemyMap = new Map()
        for (const enemy of this.state.enemies) {
            this.enemyMap.set(enemy.id, enemy)
        }

        this.state.dt = input.dt
        this.state.seed = input.seed
        this.state.levelState.totalTime = input.totalTime

        this.removeDeadEntity()
        if (this.quadTree) {
            this.quadTree.clear()
            this.state.enemies.forEach((v) => {
                this.quadTree.insert(v)
            })
        }
    }

    /** 角色移动 */
    actorMove(input: IActorMove, state: IState): IState {

        const id = toFixed(input.id)
        const dt = toFixed(input.dt)
        const x = toFixed(input.direction.x)
        const y = toFixed(input.direction.y)

        this.state = state
        const actor = this.state.actors.find((v) => v.id === id)

        if (actor) {
            const speed = AttributeManager.Ins.moveSpeed
            actor.position.x = toFixed(actor.position.x) + toFixed(toFixed(x * dt) * speed)
            actor.position.y = toFixed(actor.position.y) + toFixed(toFixed(y * dt) * speed)
            actor.direction = { x, y }
            const fixRange = 100
            if (actor.position.x > G.StageSize.w / 2 - fixRange) {
                actor.position.x = G.StageSize.w / 2 - fixRange
            } else if (actor.position.x < -G.StageSize.w / 2 + fixRange) {
                actor.position.x = -G.StageSize.w / 2 + fixRange
            }

            if (actor.position.y > G.StageSize.h / 2 - fixRange) {
                actor.position.y = G.StageSize.h / 2 - fixRange
            } else if (actor.position.y < -G.StageSize.h / 2 + fixRange) {
                actor.position.y = -G.StageSize.h / 2 + fixRange
            }
        }

        for (const weapon of this.state.weapons) {
            if (weapon.owner === id && weapon.targetId === -1) {
                weapon.direction = { x, y }
            }
        }

        return state
    }
    behaviorTreeTick(dt: number) {
        for (const tree of this.behaviorTreeMap) {
            tree[1].tick(dt)
        }
    }
    enemyTick(dt: number) {
        for (const { id, agentId } of this.state.enemies) {
            const { x, y } = this.simulator.getAgentPosition(agentId)
            const direction = this.simulator.getAgentPrefVelocity(agentId)
            const newDirection = RVOMath.normalize(new Vector2(toFixed(direction.x), toFixed(direction.y)))

            const enemy = this.enemyMap.get(id)
            if (enemy && enemy.state !== StateTypeEnum.dead) {
                enemy.recoverHP = 0
                enemy.isBeHit = 0
                enemy.direction = { x: newDirection.x, y: newDirection.y }
                enemy.position = { x: toFixed(x), y: toFixed(y) }
                enemy.aliveTime = toFixed(enemy.aliveTime + dt)

                if (enemy.state === StateTypeEnum.standCastingTime) {
                    enemy.state = StateTypeEnum.standCastingTime
                } else if (enemy.state === StateTypeEnum.impact) {
                    enemy.state = StateTypeEnum.impact
                } else {
                    enemy.state = StateTypeEnum.run
                }
            }
        }
    }

    /** 科技卷轴 */
    scrollTick(dt: number) {

        for (const scroll of this.state.scrolls) {
            scroll.state = StateTypeEnum.dead
        }

    }

    /** 怪物技能 */
    enemySkillTick(dt: number) {
        for (const enemySkill of this.state.enemySkills) {
            const { owner, type, state } = enemySkill

            if (
                type === EnemySkillTypeEnum.enemyGun
                || type === EnemySkillTypeEnum.enemyImpact
                || type === EnemySkillTypeEnum.enemyImpactPlus
            ) {

                this.enemySearchActor(enemySkill, dt)
                // 有目标 蓄力攻击
                if (state === StateTypeEnum.castingTime || state === StateTypeEnum.standCastingTime) {
                    this.casting(enemySkill, dt)
                } else if (
                    (type === EnemySkillTypeEnum.enemyImpact || type === EnemySkillTypeEnum.enemyImpactPlus)
                    && state === StateTypeEnum.impact
                ) {// 正在冲锋
                    enemySkill.during += dt
                    // 冲锋结束
                    if (
                        (type === EnemySkillTypeEnum.enemyImpact && enemySkill.during > GEnemyImpact.duration)
                        || (type === EnemySkillTypeEnum.enemyImpactPlus && enemySkill.during > GEnemyImpactPlus.duration)
                    ) {
                        const enemy = this.enemyMap.get(owner)
                        enemySkill.state === StateTypeEnum.none
                        if (enemy) {
                            enemy.state = StateTypeEnum.none
                            enemySkill.during = 0
                            enemySkill.attackPos = null
                        }
                    }
                }
            } else if (type === EnemySkillTypeEnum.recoverHpHalo) {
                SkillManager.Ins.recoverHpHalo(enemySkill, dt)
            }
        }
    }

    /** 怪物buff */
    enemyBuffTick(dt: number) {

    }
    /** 蓄力 */
    casting(enemySkill: IEnemySkill, dt: number) {
        const { owner, type, attackPos } = enemySkill
        enemySkill.castingTime = toFixed(enemySkill.castingTime) + dt

        // 蓄力完成
        if (enemySkill.castingTime >= G.CastingTime) {
            enemySkill.castingTime = 0
            const enemy = this.enemyMap.get(owner)

            if (enemy && attackPos && enemy.state !== StateTypeEnum.dead) {
                if (type === EnemySkillTypeEnum.enemyGun) {// 发射子弹
                    this.addEnemyBullet(enemySkill, attackPos, enemy)
                    enemySkill.attackPos = null
                } else if (type === EnemySkillTypeEnum.enemyImpact || type === EnemySkillTypeEnum.enemyImpactPlus) {// 冲锋
                    enemySkill.during = 0
                    enemySkill.state = StateTypeEnum.impact
                    enemy.state = StateTypeEnum.impact
                }
            }
        }
    }
    weaponTick(dt: number) {

        for (const weapon of this.state.weapons) {

            const { position, owner } = weapon

            const actor = this.state.actors.find(v => v.id === owner)
            if (actor) {
                const x = toFixed(position.x + actor.position.x)
                const y = toFixed(position.y + actor.position.y)

                weapon.shootCD = toFixed(weapon.shootCD + dt)
                weapon.searchCD = toFixed(weapon.searchCD + dt)

                this.weaponSearchEnemy(weapon, x, y)
                this.weaponShoot(weapon, x, y)
            }
        }
    }

    bulletTick(dt: number) {

        // 玩家子弹
        for (const bullet of this.state.bullets) {
            const x = toFixed(bullet.position.x)
            const y = toFixed(bullet.position.y)
            const direction = { x: toFixed(bullet.direction.x), y: toFixed(bullet.direction.y) }
            const {
                type,
                filterId,
                ownerWeapon
            } = bullet

            bullet.state = StateTypeEnum.none
            bullet.aliveTime = toFixed(bullet.aliveTime + dt)
            bullet.position = {
                x: toFixed(x + dt * toFixed(direction.x) * GMoveSpeed[type]),
                y: toFixed(y + dt * toFixed(direction.y) * GMoveSpeed[type]),
            }

            let enemy = this.bulletSerachEnemy(type, x, y, filterId)
            /** 监测到命中了敌人 */
            if (enemy) {

                const { finalDamage, isCrit } = DamageCountManager.Ins.getDamageByWeapon(bullet)
                let reduceHp = finalDamage
                if (enemy.hp < finalDamage) {
                    reduceHp = enemy.hp
                }
                enemy.hp -= finalDamage
                DamageCountManager.Ins.updateDamage(ownerWeapon, reduceHp)

                if (enemy.hp <= 0) {
                    enemy.state = StateTypeEnum.dead
                    enemy.direction = direction
                    this.addExpBall(enemy.position)
                    this.addScroll(enemy)
                } else {
                    enemy.isBeHit = 1
                }
                if (isCrit) {
                    bullet.state = StateTypeEnum.hitCrit
                    SkillManager.Ins.xingYunZiDan(bullet)
                } else {
                    bullet.state = StateTypeEnum.hit
                }
                if (enemy.absorbBullet) {
                    bullet.penetrate = -1
                } else {
                    bullet.penetrate--
                }
                if (bullet.penetrate < 0) {
                    bullet.state = StateTypeEnum.dead
                    if (isCrit) {
                        bullet.state = StateTypeEnum.deadCrit
                    }
                }
                bullet.filterId.push(enemy.id)
            } else if (bullet.aliveTime > GBulletLiveTime[type]) { // 子弹存活时间结束
                bullet.state = StateTypeEnum.dead
            }

        }

        // 怪物子弹
        for (const bullet of this.state.enemyBullets) {
            const {
                position: { x, y },
                direction,
                type,
                damage,
            } = bullet

            bullet.aliveTime = toFixed(bullet.aliveTime + dt)
            bullet.position = {
                x: toFixed(x + toFixed(dt * direction.x) * GMoveSpeed[type]),
                y: toFixed(y + toFixed(dt * direction.y) * GMoveSpeed[type]),
            }
            let actor = this.getClosestActor(bullet.position, GBulletRadius[type])
            /** 监测到命中了玩家 */
            if (actor) {

                HPManager.Ins.actorReduceHP(actor, damage)
                bullet.state = StateTypeEnum.dead
            } else if (bullet.aliveTime > GBulletLiveTime[type]) { // 子弹存活时间结束
                bullet.state = StateTypeEnum.dead
            }
        }
    }

    expTick() {

        for (const actor of this.state.actors) {
            if (actor.skillPoint > 0) {
                this.state.isPause = 1
            }
        }

        for (const exp of this.state.exps) {
            for (const actor of this.state.actors) {
                const range = AttributeManager.Ins.getExpRange()
                if (distanceSqu(exp.pos, actor.position) < range ** 2) {
                    exp.state = StateTypeEnum.dead
                    this.state.playerExp += AttributeManager.Ins.getExpGrowth()
                    SkillManager.Ins.jingYanDaRen()
                    break
                }
            }
        }

        if (this.state.playerExp >= GExp[this.state.playerLevel].exp) {
            this.state.playerLevel++
            for (const actor of this.state.actors) {
                actor.skillPoint++
            }
        }

    }
    redXTick(dt: number) {
        for (let i = this.state.redXs.length - 1; i >= 0; i--) {
            const redX = this.state.redXs[i]
            redX.time -= dt
            if (redX.time <= 0) {
                redX.state = StateTypeEnum.dead
                this.addEnemy(redX.enemyType, redX.position, redX.hpRatio, redX.partId)
            }
        }
    }
    gameTick(dt: number) {
        const levelState = this.state.levelState
        if (levelState.levelType == LevelTypeEnum.boss) {
            this.runBossLevel(dt)
        } else if (levelState.levelType == LevelTypeEnum.normal) {
            this.runNormalLevel(dt)
        }

        //添加怪物
        for (const index in levelState.partEnemyTime) {
            levelState.partEnemyTime[index].time -= dt
            if (levelState.partEnemyTime[index].time <= 0) {
                this.generateEnemy(index)
            }
        }

        if (levelState.level > levelState.totalLevel) {//游戏结束
            this.state.isPause = 1
            this.state.state = StateTypeEnum.win
            return
        }

    }

    /** boss关卡运行 */
    runBossLevel(dt: number) {
        const levelState = this.state.levelState
        if (levelState.bossArr.length <= 0) {
            //下一关
            levelState.level++
            this.setLevelData(this.state)
        }
    }
    /** 普通关卡运行 */
    runNormalLevel(dt: number) {
        const levelState = this.state.levelState
        if (levelState.levelTime <= 0) {
            //下一关
            levelState.level++
            this.setLevelData(this.state)
        }
        levelState.normalLevelTime += dt
        levelState.levelTime -= dt
    }

    /** 生成怪物 */
    generateEnemy(index: string) {
        const levelState = this.state.levelState
        const chapter = GChapter[levelState.chapter][levelState.level]
        const hpRatio = chapter.hpRatio
        const partId = Number(index)
        const { cd, enemyId, number, type } = GLevelPart[partId]
        levelState.partEnemyTime[partId].time = cd

        for (let k = 0; k < levelState.partEnemyTime[partId].number; k++) {
            let pos: IVec2 | undefined
            if (type === 2) {
                pos = this.getRandomPosFarAwayActor()
            }
            let tag = 1
            if (this.getRandom() < 0.5) {
                tag = 0
            }
            for (let i = 0; i < number; i++) {
                if (pos) {
                    const size = this.getEntitySizeByType(GEnemy[enemyId].entityType)
                    if ((i + tag) % 2 == 0) {
                        pos.x += size.w / 2 * i + this.getRandom() * 10 - 5
                    } else {
                        pos.y += size.h / 2 * i + this.getRandom() * 10 - 5
                    }
                }
                this.addRedX(enemyId, hpRatio, partId, pos)
            }
        }
    }

    actorTick(dt: number) {
        const actor = this.state.actors[0]
        if (actor.state == StateTypeEnum.dead) {
            this.state.isPause = 1
            this.state.state = StateTypeEnum.lost
            return
        }

        if (actor.beHitCD > 0) {
            actor.beHitCD -= dt
            return
        }
        const cir: circle = { r: 0, p: actor.position }
        const enemies = this.quadTree.retrieveByCircule(cir)

        const p1 = actor.position
        for (const enemy of enemies) {
            if (actor.beHitCD > 0) {
                break
            }
            const p2 = new Vector2(enemy.position.x, enemy.position.y)
            const dis1 = distance(p1, p2)
            if (dis1 - this.getEntitySizeByType(enemy.type).w < 0) {
                HPManager.Ins.actorReduceHP(actor, 1)
                actor.beHitCD = 1
            }
        }

    }
    /** 怪物搜角色目标 */
    enemySearchActor(enemySkill: IEnemySkill, dt: number) {
        const { type, owner } = enemySkill

        if (enemySkill.attackPos === null && enemySkill.CD > GSEnemySKillCD[type]) {
            const enemy = this.enemyMap.get(owner)
            if (enemy && enemy.state !== StateTypeEnum.dead) {
                const targetPos = this.getClosestActor(enemy.position, GWeaponShootRadiu[type])?.position || null
                if (targetPos) {
                    enemySkill.attackPos = { x: targetPos.x, y: targetPos.y }
                }
                if (enemySkill.attackPos !== null) {
                    // 怪物蓄力
                    if (type === EnemySkillTypeEnum.enemyGun) {
                        enemy.state = StateTypeEnum.castingTime
                        enemySkill.state = StateTypeEnum.castingTime
                    } else if ((type === EnemySkillTypeEnum.enemyImpact || type === EnemySkillTypeEnum.enemyImpactPlus) && targetPos) {
                        enemy.state = StateTypeEnum.standCastingTime
                        enemySkill.state = StateTypeEnum.standCastingTime
                        enemySkill.attackPos = { x: targetPos.x - enemy.position.x, y: targetPos.y - enemy.position.y }
                    }
                    enemySkill.CD = 0
                }
            }
        } else {
            enemySkill.CD = toFixed(enemySkill.CD + dt)
        }
    }

    /** 玩家武器搜索目标 */
    weaponSearchEnemy(weapon: IWeapon, x: number, y: number) {

        if (weapon.searchCD < G.SearchCD) {
            return
        }
        const r = AttributeManager.Ins.getWeaponAttr(weapon).aimRadiu
        const sr = AttributeManager.Ins.getWeaponAttr(weapon).shootRadiu
        const cir: circle = { r, p: { x, y } }
        const enemies = this.quadTree.retrieveByCircule(cir)
        let tempEnemy: IEnemy | null = null
        const searchType = SkillManager.Ins.qiRuanPengYing(weapon)

        for (const enemy of enemies) {
            const p1 = new Vector2(x, y)
            const p2 = new Vector2(enemy.position.x, enemy.position.y)
            const dis1 = distance(p1, p2)
            // 武器怪物距离小于瞄准距离
            if (dis1 - this.getEntitySizeByType(enemy.type).w < r) {
                if (!tempEnemy) {
                    tempEnemy = enemy
                } else {
                    const p3 = new Vector2(tempEnemy.position.x, tempEnemy.position.y)
                    const dis2 = distance(p1, p3)
                    if (searchType == 1 && dis1 < sr) {
                        if (tempEnemy.hp < enemy.hp) {// 生命更高的怪
                            tempEnemy = enemy
                        } else if (tempEnemy.hp == enemy.hp && dis1 < dis2) {
                            tempEnemy = enemy
                        }
                    } else if (searchType == 2 && dis1 < sr) {
                        if (tempEnemy.hp > enemy.hp) {// 生命更低的怪
                            tempEnemy = enemy
                        } else if (tempEnemy.hp == enemy.hp && dis1 < dis2) {
                            tempEnemy = enemy
                        }
                    } else {
                        if (dis1 < dis2) {// 距离更近的怪物
                            tempEnemy = enemy
                        }
                    }
                }
            }
        }
        weapon.targetId = tempEnemy?.id || -1
        weapon.searchCD = 0
    }

    /** 武器射击 */
    weaponShoot(weapon: IWeapon, x: number, y: number) {
        const weaponData = AttributeManager.Ins.getWeaponAttr(weapon)
        weapon.state = StateTypeEnum.none

        if (weapon.targetId === -1) {
            return
        }

        // 有瞄准了的敌人
        const targetEnemy = this.enemyMap.get(weapon.targetId)
        if (!targetEnemy) {
            return
        }

        // 武器进行瞄准
        const p3 = getDirByPos(targetEnemy.position.x, targetEnemy.position.y, x, y)

        weapon.direction.x = p3.x
        weapon.direction.y = p3.y

        const dis1 = toFixed(toFixed(x - targetEnemy.position.x) ** 2) +
            toFixed(toFixed(y - targetEnemy.position.y) ** 2) -
            this.getEntitySizeByType(targetEnemy.type).w ** 2
        const dis2 = (weaponData.shootRadiu) ** 2

        // 在射程外，或开枪cd中
        if (dis1 >= dis2 || weapon.shootCD < weaponData.shootCD) {
            return
        }

        weapon.state = StateTypeEnum.shoot
        this.addBullet(weapon, weaponData, p3, x, y)
        weapon.shootCD = 0

        SkillManager.Ins.tongBuSheJi(weapon, targetEnemy)
    }

    /** 子弹遍历敌人 */
    bulletSerachEnemy(type: EntityTypeEnum, x: number, y: number, filterId: number[]): IEnemy | null {
        let tempEnemy: IEnemy | null = null
        const cir: circle = { r: GBulletRadius[type], p: { x, y } }
        const enemies = this.quadTree.retrieveByCircule(cir) as IEnemy[]

        for (const enemy of enemies) {
            if (enemy.hp <= 0 || filterId.includes(enemy.id)) {
                continue
            }
            const p1 = new Vector2(x, y)
            const p2 = new Vector2(enemy.position.x, enemy.position.y)
            let width = this.getEntitySizeByType(enemy.type).w / 2
            const dis1 = distance(p1, p2)
            if (dis1 < GBulletRadius[type] + width) {
                if (!tempEnemy) {
                    tempEnemy = enemy
                } else {
                    const p3 = new Vector2(tempEnemy.position.x, tempEnemy.position.y)
                    const dis2 = distance(p1, p3)
                    if (dis2 > dis1) {
                        tempEnemy = enemy
                    }
                }
            }
        }
        return tempEnemy
    }

    addRedX(enemyType: EntityTypeEnum, hpRatio: number, partId: number, bornPos?: IVec2) {
        const pos: IVec2 = bornPos || this.getRandomPosFarAwayActor()

        const redX: IRedX = {
            id: this.state.nextId++,
            position: deepClone(pos),
            time: 1.6,
            enemyType,
            state: StateTypeEnum.idle,
            hpRatio,
            partId
        }

        this.state.redXs.push(redX)
    }

    addEnemy(type: EntityTypeEnum, pos: IVec2, hpRatio: number, partId: number) {

        this.setEnemyAgent(type)

        const enemy: IEnemy = {
            id: this.state.nextId++,
            agentId: this.addAgent(pos, type),
            type,
            position: pos,
            direction: { x: 0, y: 0 },
            hpMax: GEnemyHP[type] * hpRatio,
            hp: GEnemyHP[type] * hpRatio,
            aliveTime: 0,
            state: StateTypeEnum.none,
            isBeHit: 0,
            partId,
        }

        /** 设置怪物质量 */
        if (GEnemy[type].enemyType === EnemyTypeEnum.normal) {
            this.simulator.setAgentMass(enemy.agentId, G.normalMass)
        } else if (GEnemy[type].enemyType === EnemyTypeEnum.elite) {
            this.simulator.setAgentMass(enemy.agentId, G.eliteMass)
        } else if (GEnemy[type].enemyType === EnemyTypeEnum.boss) {
            this.simulator.setAgentMass(enemy.agentId, G.bossMass)
        }
        this.state.enemies.push(enemy)

        // 给特殊怪添加武器，boss添加行为树
        if (
            type === EntityTypeEnum.enemy_shooter ||
            type === EntityTypeEnum.enemy_shooter_plus
        ) {
            this.addEnemySkill(enemy, EnemySkillTypeEnum.enemyGun)
        } else if (
            type === EntityTypeEnum.enemy_soldier ||
            type === EntityTypeEnum.enemy_soldier_plus
        ) {
            this.addEnemySkill(enemy, EnemySkillTypeEnum.enemyImpact)
        } else if (GEnemy[type].enemyType === EnemyTypeEnum.boss) {
            this.addBehaviorTree(enemy)
            enemy.shootCD = 0
            enemy.impactCD = 0
            enemy.standCastingTime = 0
            enemy.during = 0
        } else if (type === EntityTypeEnum.enemy_support_r) {
        } else if (type === EntityTypeEnum.enemy_support_g) {
            this.addEnemySkill(enemy, EnemySkillTypeEnum.recoverHpHalo)
        } else if (type === EntityTypeEnum.enemy_support_b) {
        } else if (type === EntityTypeEnum.enemy_cattle || type === EntityTypeEnum.enemy_cattle_plus) {
            this.addEnemySkill(enemy, EnemySkillTypeEnum.enemyImpactPlus)
        } else if (type === EntityTypeEnum.enemy_shield) {
            enemy.absorbBullet = 1
        } else if (type === EntityTypeEnum.enemy_rebound) {
        } else if (type === EntityTypeEnum.enemy_reward) {
        }

    }

    /** 怪物添加技能 */
    addEnemySkill(enemy: IEnemy, type: EnemySkillTypeEnum) {
        const enemySkill: IEnemySkill = {
            owner: enemy.id,
            type: type,
            CD: GSEnemySKillCD[type],
            castingTime: 0,
            attackPos: null,
            state: StateTypeEnum.none,
            id: this.state.nextId++,
            during: 0,
        }
        this.state.enemySkills.push(enemySkill)
    }

    /** 添加行为树 */
    addBehaviorTree(enemy: IEnemy) {
        const { type, id } = enemy
        let tree = new Boss2Tree(enemy, this.state)
        if (type === EntityTypeEnum.boss_1) {
            tree = new Boss1Tree(enemy, this.state)
        }

        this.behaviorTreeMap.set(id, new BehaviorManager(tree))
    }

    /** 添加子弹 */
    addBullet(weapon: IWeapon, weaponData: IWeaponAttr, p3: IVec2, x: number, y: number) {
        const { entityType } = weapon

        const pos = GWeaponMuzzle[entityType]
        let point = new Vector2(pos.x, pos.y)
        let angel = vecToAngel(weapon.direction.x, weapon.direction.y)

        point = rotate(point, new Vector2(0, 0), angelToRadian(angel))
        point.x = toFixed(point.x)
        point.y = toFixed(point.y)

        if (entityType === EntityTypeEnum.weapon1 || entityType === EntityTypeEnum.weapon3) {
            let num = weaponData.special || 0
            let angle = GWeapon1BulletAttr.angle
            if (entityType === EntityTypeEnum.weapon3) {
                angle = GWeapon3BulletAttr.angle
            }
            for (let i = -(Math.floor(num / 2)); i < num / 2 + 1; i++) {
                let vec2 = new Vector2(toFixed(p3.x), toFixed(p3.y))
                vec2 = rotate(vec2, new Vector2(0, 0), angelToRadian(angle * i - num % 2))
                const bullet = this.getBulletByWeapon(weapon, vec2, point, x, y)
                this.state.bullets.push(bullet)
            }
        } else if (entityType === EntityTypeEnum.weapon5) {
            let vec2 = new Vector2(toFixed(p3.x), toFixed(p3.y))
            vec2 = rotate(vec2, new Vector2(0, 0), angelToRadian(this.getRandom() * 20 - 10))
            const bullet = this.getBulletByWeapon(weapon, vec2, point, x, y)
            this.state.bullets.push(bullet)
            if (SkillManager.Ins.shengMingSheJi(weapon)) {
                // 生命不足1时不扣血
                if (this.state.actors[0].hp > 1) {
                    HPManager.Ins.actorReduceHP(this.state.actors[0], 1)
                }
            }

        } else if (SkillManager.Ins.huoLiBuZuKongJuZheng(weapon)) {

            const p = RVOMath.normalize(new Vector2(p3.x, p3.y)).scale(3)
            const p1 = rotate(new Vector2(p.x, p.y), new Vector2(0, 0), angelToRadian(90))
            const p2 = rotate(new Vector2(p.x, p.y), new Vector2(0, 0), angelToRadian(-90))

            const fun = (pos: Vector2) => {
                const bullet = GameLogic.Ins.getBulletByWeapon(weapon, p3, point, x + pos.x, y + pos.y)
                bullet.damage = Math.ceil(bullet.damage / 2)
                GameLogic.Ins.state.bullets.push(bullet)
            }

            fun(p1)
            fun(p2)
        } else {
            const bullet = this.getBulletByWeapon(weapon, p3, point, x, y)
            this.state.bullets.push(bullet)
        }
    }

    addEnemyBullet(enemyGun: IEnemySkill, pos: IVec2, enemy: IEnemy) {

        const direction = RVOMath.normalize(new Vector2(pos.x - enemy.position.x, pos.y - enemy.position.y))

        this.state.enemyBullets.push({
            id: this.state.nextId++,
            owner: enemyGun.owner,
            type: EntityTypeEnum.bullet3,
            aliveTime: 0,
            position: {
                x: toFixed(enemy.position.x),
                y: toFixed(enemy.position.y),
            },
            direction: {
                x: direction.x,
                y: direction.y,
            },
            state: StateTypeEnum.none,
            penetrate: 0,
            filterId: [],
            damage: 1,
            ownerWeapon: enemyGun.id,
            critChance: 0,
            critRate: 0,
        })
    }

    addBulletByBoss(enemy: IEnemy) {
        const actor = this.getClosestActor(enemy.position, G.StageSize.w)
        if (actor) {
            const vec2 = new Vector2(actor.position.x - enemy.position.x, actor.position.y - enemy.position.y)
            const direction = RVOMath.normalize(vec2)
            this.state.enemyBullets.push({
                id: this.state.nextId++,
                owner: enemy.id,
                type: EntityTypeEnum.bullet3,
                aliveTime: 0,

                position: {
                    x: toFixed(enemy.position.x),
                    y: toFixed(enemy.position.y),
                },
                direction: {
                    x: direction.x,
                    y: direction.y,
                },
                state: StateTypeEnum.none,
                penetrate: 0,
                filterId: [],
                damage: 1,
                ownerWeapon: enemy.id,
                critChance: 0,
                critRate: 0
            })
        }
    }

    /** 掉落经验球 */
    addExpBall(position: IVec2, state?: IState) {
        if (state) this.state = state
        const exp: IExp = {
            type: ExpTypeEnum.exp_blue,
            pos: position,
            state: StateTypeEnum.idle,
            id: this.state.nextId++,
        }

        this.state.exps.push(exp)
    }

    /** 掉落经验卷轴 */
    addScroll(enemy: IEnemy) {

        // boss
        if (GEntity[enemy.type].type === EntityTypeEnum2.boss) {
            if (TalentManager.Ins.getScrollTalent()) {
                BagManager.Ins.obtainScroll(2)
            } else {
                BagManager.Ins.obtainScroll(1)
                this.state.scrollNum += 1
            }
            this.state.scrolls.push({
                id: this.state.nextId++,
                pos: enemy.position,
                state: StateTypeEnum.idle,
            })
        }

    }

    /** 移除已经死掉的对象 */
    removeDeadEntity() {

        for (let index = this.state.enemies.length - 1; index >= 0; index--) {
            const enemy = this.state.enemies[index]
            if (enemy.state === StateTypeEnum.dead) {
                const enemyGun = this.state.enemySkills.find(v => v.owner === enemy.id)
                if (enemyGun) {
                    enemyGun.state = StateTypeEnum.dead
                }
                this.simulator.removeAgent(enemy.agentId)
                this.state.enemies.splice(index, 1)[0]
                if (this.behaviorTreeMap.has(enemy.id)) {
                    this.behaviorTreeMap.delete(enemy.id)
                }

                // 移除boss标记
                if (GEnemy[enemy.type].enemyType === EnemyTypeEnum.boss) {

                    const index = this.state.levelState.bossArr.findIndex((v) => v == enemy.partId)
                    if (index != -1) {
                        this.state.levelState.bossArr.splice(index, 1)
                    }
                }
            }
        }

        for (let index = this.state.bullets.length - 1; index >= 0; index--) {
            if (this.state.bullets[index].state === StateTypeEnum.dead) {
                this.state.bullets.splice(index, 1)
            }
        }

        for (let index = this.state.enemyBullets.length - 1; index >= 0; index--) {
            if (this.state.enemyBullets[index].state === StateTypeEnum.dead) {
                this.state.enemyBullets.splice(index, 1)
            }
        }

        for (let index = this.state.enemySkills.length - 1; index >= 0; index--) {
            if (this.state.enemySkills[index].state === StateTypeEnum.dead) {
                this.state.enemySkills.splice(index, 1)
            }
        }
        for (let index = this.state.exps.length - 1; index >= 0; index--) {
            if (this.state.exps[index].state === StateTypeEnum.dead) {
                this.state.exps.splice(index, 1)
            }
        }
        for (let i = this.state.redXs.length - 1; i >= 0; i--) {
            if (this.state.redXs[i].state == StateTypeEnum.dead) {
                this.state.redXs.splice(i, 1)
            }
        }
        for (let i = this.state.scrolls.length - 1; i >= 0; i--) {
            if (this.state.scrolls[i].state == StateTypeEnum.dead) {
                this.state.scrolls.splice(i, 1)
            }
        }
    }

    /** 添加rvo代理 */
    addAgent(pos: IVec2, type: EntityTypeEnum): number {
        const { x, y } = pos
        const id = this.simulator.addAgent(new Vector2(x, y))
        if (
            type === EntityTypeEnum.enemy_soldier
            || type === EntityTypeEnum.enemy_soldier_plus
            || type === EntityTypeEnum.enemy_cattle
            || type === EntityTypeEnum.enemy_cattle_plus
        ) {
            this.simulator.getAgentByAid(id).maxSpeed_ = GMoveSpeed[type] * 10
        } else {
            // 每个怪物移速上限为5倍默认移速
            this.simulator.getAgentByAid(id).maxSpeed_ = GMoveSpeed[type] * 5
        }
        return id
    }

    /** 初始化rvo参数 */
    initAgent(simulator: Simulator, ap?: AgentParam) {
        this.simulator = simulator
        const agentParam: AgentParam = ap || {
            neighborDist: 300,
            maxNeighbors: 10,
            timeHorizon: 1,
            timeHorizonObst: 1,
            radius: 20,
            maxSpeed: 15,
            velocity: new Vector2(1, 0)
        }
        this.simulator.setAgentDefaults(agentParam)
        const fixRange = 25
        const vertices = [
            new Vector2(G.StageSize.w / 2 - fixRange, G.StageSize.h / 2 - fixRange), // 第一个顶点坐标
            new Vector2(G.StageSize.w / 2 - fixRange, fixRange - G.StageSize.h / 2),  // 第四个顶点坐标
            new Vector2(fixRange - G.StageSize.w / 2, fixRange - G.StageSize.h / 2), // 第三个顶点坐标
            new Vector2(fixRange - G.StageSize.w / 2, G.StageSize.h / 2 - fixRange), // 第二个顶点坐标
        ];

        this.simulator.addObstacle(vertices);
        this.simulator.processObstacles()
    }

    setEnemyAgent(type: EntityTypeEnum) {

        const radius = this.getEntitySizeByType(type).w / 2
        const agentParam: AgentParam = {
            neighborDist: radius * 3.5,
            maxNeighbors: 20,
            timeHorizon: radius,
            timeHorizonObst: 2,
            radius: radius - 2,
            maxSpeed: 30,
            velocity: new Vector2(1, 0)
        }
        this.simulator.setAgentDefaults(agentParam)

    }

    /** 怪物rvo避障移动 */
    setPreferredVelocities() {

        for (const enemy of this.state.enemies) {
            const { agentId, type, state, id } = enemy
            // 当前坐标
            const agentPos = this.simulator.getAgentPosition(agentId)

            // 目标坐标
            let runPos = this.getEnemyTargetPos(enemy, agentPos)

            if (!runPos) {
                continue
            }

            // 移动方向
            let goalVector = new Vector2(runPos.x, runPos.y).minus(agentPos)
            // 速度
            let speed = GMoveSpeed[type]
            if (state === StateTypeEnum.standCastingTime) { // 站立蓄力
                goalVector = goalVector.scale(1 / 10000)
            } else if (state === StateTypeEnum.impact) { // 冲锋状态，增加移速，不可转向
                speed = GEnemyImpact.speed
                const dir = enemy.attackPos || this.state.enemySkills.find(v => v.owner === id)?.attackPos || null
                if (dir) {
                    goalVector = new Vector2(toFixed(dir.x), toFixed(dir.y))
                }
            }
            if (RVOMath.absSq(goalVector) > 1) {
                goalVector = RVOMath.normalize(goalVector).scale(speed)
            }
            if (RVOMath.absSq(goalVector) < RVOMath.RVO_EPSILON) {
                goalVector = new Vector2(0, 0)
                this.simulator.setAgentPrefVelocity(agentId, goalVector)
            } else {
                this.simulator.setAgentPrefVelocity(agentId, goalVector)

                let angel = toFixed(this.getRandom() * 10 * Math.PI);
                let dist = toFixed(this.getRandom() * 0.001);

                this.simulator.setAgentPrefVelocity(
                    agentId,
                    this.simulator.getAgentPrefVelocity(agentId)
                        .plus(new Vector2(toFixed(Math.cos(angel)), Math.sin(angel)).scale(dist))
                )
            }
        }
    }

    /** 获取怪物移动目标的坐标 */
    getEnemyTargetPos(enemy: IEnemy, agentPos: Vector2): IVec2 | null {
        const { type, position: { x, y } } = enemy
        let targetPos = { x, y }
        const moveType = GEnemy[type].moveType

        if (moveType == EnemyMoveTypeEnum.saveToActor) {
            targetPos = this.getDisPlayerEnemyTargetPos(agentPos, type)
        } else if (moveType == EnemyMoveTypeEnum.runToActor) {
            targetPos = this.getNormalEnemyTargetPos(agentPos)
        } else if (moveType == EnemyMoveTypeEnum.random) {
            targetPos = this.getRandomTargetPos(targetPos, enemy.targetPos)
            enemy.targetPos = targetPos
        } else if (moveType == EnemyMoveTypeEnum.custom) {
            targetPos = enemy.targetPos || enemy.position
        }

        return { x: toFixed(targetPos.x), y: toFixed(targetPos.y) }
    }

    /** 保持距离怪物的移动目标点 */
    getDisPlayerEnemyTargetPos(agentPos: Vector2, type: EntityTypeEnum): IVec2 {
        const targetPos = { x: 0, y: 0 }
        const radius = GEnemyDisPlayer[type] || 500
        const enemyPos = new Vector2(agentPos.x, agentPos.y)
        // 最近的玩家
        let closest = this.state.actors[0]
        // 距离太近的玩家
        const tooClosestArr: IActor[] = []
        for (const actor of this.state.actors) {

            const v1 = new Vector2(closest.position.x, closest.position.y)
            const v2 = new Vector2(actor.position.x, actor.position.y)
            const v3 = enemyPos
            const dis1 = v3.clone().minus(v1).lengthSqr()
            const dis2 = v3.clone().minus(v2).lengthSqr()

            if (dis2 - dis1 < 0) {
                closest = actor
            }

            if (dis2 < radius ** 2) {
                tooClosestArr.push(actor)
            }
        }
        const f = () => {
            const circle: circle = {
                p: new Vector2(closest.position.x, closest.position.y),
                r: GEnemyDisPlayer[type] || 500
            }

            const p = getPointInCircleByPoint(enemyPos, circle)
            targetPos.x = p.x
            targetPos.y = p.y
        }
        if (tooClosestArr.length <= 1) {// 范围内只有一个玩家
            f()
        } else if (tooClosestArr.length == 2) {// 范围内有俩玩家

            // 算两个玩家范围相交圆的点，太卡使用新的方案
            const p1 = tooClosestArr[0].position
            const p2 = tooClosestArr[1].position

            // 敌人都在同一侧
            if (
                ((p1.x > enemyPos.x && p2.x > enemyPos.x) || (p1.x <= enemyPos.x && p2.x <= enemyPos.x)) &&
                ((p1.y > enemyPos.y && p2.y > enemyPos.y) || (p1.y <= enemyPos.y && p2.y <= enemyPos.y))
            ) {
                f()
            } else {

                const p = rotateAroundCenter(new Vector2(p1.x, p1.y), new Vector2(p2.x, p2.y), 90, radius * 2)

                if (get3PointDisFar(p[0], p[1], enemyPos)) {
                    targetPos.x = p[1].x
                    targetPos.y = p[1].y
                } else {
                    targetPos.x = p[0].x
                    targetPos.y = p[0].y
                }
            }

        } else { // 周围玩家太多 不知所措 呆在原地不动
            targetPos.x = enemyPos.x
            targetPos.y = enemyPos.y
        }
        return targetPos
    }

    /** 随机移动怪物的目标点
     * @param nowPos 当前坐标
     * @param targetPos 目标坐标
     * @returns 
     */
    getRandomTargetPos(nowPos: IVec2, targetPos?: IVec2): IVec2 {
        if (!targetPos) {
            return this.getRandomPos()
        } else if (distanceSqu(nowPos, targetPos) < 3) {
            return this.getRandomPos()
        }
        return targetPos
    }

    /** 普通怪物目标点，目标玩家 */
    getNormalEnemyTargetPos(agentPos: Vector2): IVec2 {
        let target = this.state.actors[0]
        for (const actor of this.state.actors) {
            const { id } = actor
            if (id === target.id) {
                continue
            }
            const p1 = new Vector2(target.position.x, target.position.y)
            const p2 = new Vector2(actor.position.x, actor.position.y)
            if (get3PointDisFar(p1, p2, agentPos)) {
                target = actor
            }
        }
        return target?.position
    }

    /** 范围内，距离点最近的玩家 */
    getClosestActor(pos: IVec2, dis: number): IActor | null {
        let target: IActor | null = null
        let disTemp = 0
        for (const actor of this.state.actors) {
            const disSqu = distanceSqu(actor.position, pos)
            if (disSqu < toFixed(dis ** 2)) {
                if (target) {
                    if (disSqu < disTemp) {
                        target = actor
                    }
                } else {
                    target = actor
                    disTemp = disSqu
                }
            }
        }
        return target
    }

    getEntitySizeByType(type: EntityTypeEnum) {
        if (GEnemy[type]?.enemyType === EnemyTypeEnum.boss) {
            return G.BossEnemySize
        } else if (GEnemy[type]?.enemyType === EnemyTypeEnum.elite) {
            return G.EliteEntitySize
        }
        return G.NormalEntitySize
    }

    /** 获取场景内一个随机点，该点远离角色 */
    getRandomPosFarAwayActor(): IVec2 {
        let times = 10
        let pos = this.getRandomPos()
        const func = () => {
            for (const { position } of this.state.actors) {
                if (distanceSqu(pos, position) < 200 ** 2) {
                    pos = this.getRandomPos()
                    if (--times <= 0) {
                        return pos
                    } else {
                        func()
                        break
                    }
                }
            }
        }
        func()
        return pos
    }

    /** 获取场景内一个随机点 */
    getRandomPos(): IVec2 {
        return {
            x: toFixed(G.StageSize.w / 2 - 100 - this.getRandom() * (G.StageSize.w - 200)),
            y: toFixed(G.StageSize.h / 2 - 100 - this.getRandom() * (G.StageSize.h - 200)),
        }
    }

    getRandom() {
        this.state.seed = randomBySeed(this.state.seed)
        return toFixed(this.state.seed / 233280)
    }

    /** 设置该关信息 */
    setLevelData(state: IState) {
        const levelState = state.levelState
        const chapter = levelState.chapter
        const level = levelState.level
        const partData = GChapter[chapter][level]
        if (!partData) return

        levelState.levelType = partData.levelType
        levelState.levelTime = partData.duration || 999999

        levelState.partEnemyTime = {}
        const parts = partData.parts

        //设置小怪
        if (parts) {
            for (const id of parts) {
                if (levelState.partEnemyTime[id]) {
                    levelState.partEnemyTime[id].number++
                } else {
                    levelState.partEnemyTime[id] = {
                        time: GLevelPart[id].firstTime,
                        number: 1
                    }
                }
            }
        }

        levelState.bossArr = []
        //设置boss
        if (partData.bossArr) {
            for (const id of partData.bossArr) {
                levelState.partEnemyTime[id] = {
                    time: GLevelPart[id].firstTime,
                    number: 1
                }
                levelState.bossArr.push(id)
            }
        }

    }

    /** 设置武器在玩家身上的位置 */
    setWeaponPos(weapons: IWeapon[]) {
        const POSARR: Record<number, { x: number, y: number }[]> = {
            1: [{ x: 0, y: -35 }],
            2: [{ x: 40, y: -25 }, { x: -40, y: -25 }],
            3: [{ x: 40, y: -25 }, { x: -40, y: -25 }, { x: -40, y: 25 }],
            4: [{ x: 40, y: -25 }, { x: -40, y: -25 }, { x: -40, y: 25 }, { x: 40, y: 25 }],
            5: [{ x: 40, y: -25 }, { x: -40, y: -25 }, { x: -55, y: 25 }, { x: 55, y: 25 }, { x: 0, y: 45 }],
            6: [{ x: 40, y: -50 }, { x: -40, y: -50 }, { x: -40, y: 50 }, { x: 40, y: 50 }, { x: 60, y: 0 }, { x: -60, y: 0 }],
        }
        const weaponOwner: Record<number, IWeapon[]> = {}
        for (const weapon of weapons) {
            if (!weaponOwner[weapon.owner]) {
                weaponOwner[weapon.owner] = []
            }
            weaponOwner[weapon.owner].push(weapon)
        }

        for (const i in weaponOwner) {
            const len = weaponOwner[i].length
            if (len <= 6) {
                for (const j in weaponOwner[i]) {
                    weaponOwner[i][j].position = POSARR[len][j]
                }
            } else {
                const v2 = new Vector2(0, 60 + len)
                for (const j in weaponOwner[i]) {
                    const pos = rotate(v2, new Vector2(0, 0), 2 * Math.PI / len * Number(j))
                    weaponOwner[i][j].position = pos
                }
            }
        }

    }

    /** 通过武器生成子弹
     * @param weapon 武器
     * @param vec2 方向
     * @param point 枪口坐标
     * @param x 
     * @param y
     * @returns 
     */
    getBulletByWeapon(weapon: IWeapon, vec2: Vector2 | IVec2, point: Vector2, x: number, y: number): IBullte {
        const { owner, id, entityType } = weapon
        const { penetrate, damage, critChance, critRate } = AttributeManager.Ins.getWeaponAttr(weapon)
        return {
            id: this.state.nextId++,
            type: GWeaponBullet[entityType],
            owner,
            aliveTime: 0,
            position: {
                x: toFixed(x + point.x * 5),
                y: toFixed(y + point.y * 5),
            },
            direction: {
                x: toFixed(vec2.x),
                y: toFixed(vec2.y),
            },
            state: StateTypeEnum.none,
            penetrate,
            filterId: [],
            damage,
            ownerWeapon: id,
            critChance,
            critRate,
        }
    }

    /** 恢复 */
    regenerationTick(dt: number) {
        if (this.state.actors[0].regenerationCD <= 0) {
            let regenerationHP = HPManager.Ins.getRegenerationHP()
            this.state.actors[0].hp += regenerationHP
            this.state.actors[0].regenerationCD = 10
        } else {
            this.state.actors[0].regenerationCD -= dt
        }
    }

    setState(state: IState) {
        this.state = state
    }
}